perm filename ALAID.PAL[HAL,HE]1 blob
sn#170620 filedate 1975-07-28 generic text, type C, neo UTF8
COMMENT ⊗ VALID 00013 PAGES
C REC PAGE DESCRIPTION
C00001 00001
C00002 00002
C00003 00003 Fields and data: ALDOPS, BRKTAB
C00006 00004 INTERP
C00009 00005 VALPRN, VARPRN
C00010 00006 TYPVAL
C00013 00007 I/O routines: TYPR50, INCHR, INOCT, INR50
C00017 00008 BRACE
C00021 00009 take care of break case
C00027 00010 NEWBRK, FNDBRK
C00029 00011 TPPSOP
C00032 00012 TYPADR, TYPOFS, INADR, INOFS
C00034 00013 Not yet implemented
C00035 ENDMK
C⊗;
COMMENT ⊗
.TITLE Test of ALAID
.INSRT HALHED.PAL[HAL,HE]
.INSRT K1DEF.PAL[11,SYS]
.INSRT HALIO.PAL[HAL,HE]
⊗
;Fields and data: ALDOPS, BRKTAB
COMMENT ⊗ ALAID information resides in the ALDOPS table parallel to
the INTOPS table. Each psuedo-op has these fields: ⊗
II == 0
XX ALDFLG ;Holds bits indicating status of tracing
ALDBRK == 1 ; Break bit. When set, break on this psop.
ALDTRC == 2 ; Tracing bit. When set, trace this psop.
XX ALDARG ;Encoding the types of arguments taken by this psop.
XX ALDPNM ;The RAD50 print name of the psop. Two words
II == II + 2
OPSLTH == II/2 ;Number of words in each ALDOPS entry
.MACRO MAKEOP CNAME, ANAME, TYPES
;Compiler name, Address name, Types of arguments
II == .
0 ;ALDFLG
III == 0
II2 == 1
.IRP ARG,<TYPES>
.IF NB ARG
III == II2*ARG + III
II2 == 8*II2
.ENDC
.ENDM
III ;ALDARG
.RAD50 /ANAME/ ;ALDPNM
. = II + OPSLTH + OPSLTH;Just in case the ANAME was funny
.ENDM
A == 1
LA == 2
O == 3
LO == 4
N == 5
; The interpreter operation debug table
ALDOPS: MAKEOP XINVALID,INVALD ;Illegal instruction
.INSRT INTOPS.PAL[HAL,HE]
COMMENT ⊗ There is a fixed number of available bracepoints. (Break
or trace points). When a bracepoint is in place, the old contents of
the instruction are stored in the breakpoint table. Bracepoints are
always kept in place. ⊗
II == 0
XX OLDPSOP ;Saved contents of psinstruction
XX OLDADR ;Where it comes from
XX BRCWHA ;Flags saying what to do.
ALDBRK == 1 ; Break bit. When set, this is a break point.
ALDTRC == 2 ; Tracing bit. When set, this is a tracepoint.
BRKLTH == II/2 ;Number of words in each entry
BRKNO == 10 ;Number of breakpoints available
BRKTAB: .BLKW BRKLTH*BRKNO
BRKDUM: .BLKW BRKLTH ;One dummy break table entry for bad entries
; INTERP
.MACRO BMPIPC ;
ADD #2,IPC(R4) ;Bump IPC
.ENDM ;
COMMENT ⊗ This is the interpreter loop which replaces the one in
INTERP.PAL. It does bounds checking for the instruction, then
catches single step, special traps or traces on this instruction
type, then breakpoints or tracepoints in the code. Finally it calls
the appropriate interpeter routine. ⊗
INTERP:
MOV R3,R0 ;Save the limit of the interpreter stack for error checking.
SUB #INSTSZ-2,R0
MOV R0,-(SP) ;
INT1: CMP R3,(SP) ;Interpreter stack overflow?
BGE INT3 ;No. Go to next instruction.
HALERR INTMS3 ;Yes. Complain.
INT3: MOV @IPC(R4),R0 ;R0 ← next instruction
BLE INVALID ;Instruction out of range
CMP R0,#INSEND ;Is instruction too large?
BLE INT2 ;No.
INVALID:HALERR INTMS1 ;Yes. complain.
INT2: BMPIPC ;Bump IPC
;catch single step
BIT #ALDSS,DEBMOD(R4) ;Single step?
BEQ INT4 ;No
INT5: JSR PC,BRACE ;R0 ← proper psop to execute
BR INTDO ;Now do the instruction
;catch break on instruction type
INT4: MOV #OPSLTH,R1 ;
MUL R0,R1 ;
ADD #ALDOPS,R1 ;
MOV R1,R2 ;R2 ← pointer into ALDOPS
BIT #ALDBRK,ALDFLG(R2) ;Break?
BNE INT5 ;Yes.
;catch brace instruction
CMP #XBRACE,R0 ;Is it a brace instruction?
BEQ INT5 ;Yes.
;catch trace on instruction type
BIT #ALDTRC,ALDFLG(R2) ;Trace?
BEQ INTDO ;No.
JSR PC,TRACE ;Yes.
INTDO: JSR PC,@INTOPS(R0) ;Call the appropriate routine
BR INTCPL(R0) ;R0 should have an completion code. Branch accordingly.
INTCPL: BR INT1 ;No error. Repeat.
HALERR INTMS2 ;Error. Complain.
BR INT1 ;And repeat.
INTMS1: ASCIE /INTERPRETER INSTRUCTION OUT OF RANGE/
INTMS2: ASCIE /INTERPRETED INSTRUCTION RETURNED FAILURE/
INTMS3: ASCIE /INTERPRETER STACK OVERFLOW/
; VALPRN, VARPRN
VARPRN:
COMMENT ⊗ Interpreter routine. Prints the graph node pointed to by
the level-offset of the argument. ⊗
JSR PC,GTVAL ;Put the good value on the stack
JMP VALPRN ;And let VALPRN take it from there.
VALPRN:
COMMENT ⊗ Interpreter routine. Prints the value the top of the stack
and pops it. Uses the Floating package. ⊗
MOV (R3)+,R0 ;R0 ← LOC[value cell]
JSR PC,TYPVAL ;Go print it.
CCC ;Clear condition codes
RTS PC ;And return
; TYPVAL
TYPVAL:
COMMENT ⊗ R0 points to a value cell. Prints it according to its
type. Requires the floating package. ⊗
MOV R2,-(SP) ;Save R2
MOV R0,R2 ;R2 ← LOC[value cell]
MOV #CRLFX,R0 ;CRLF
JSR PC,TYPSTR ;
MOVB TAGID(R2),R1
CMPB #SCLID,R1 ;A scalar?
BEQ TYPVL1 ;
CMPB #VCTID,R1 ;A vector?
BEQ TYPVL4 ;
CMPB #TRNID,R1 ;A trans?
BEQ TYPVL5 ;
TYPVL1: MOV #SNAME,R0 ;
JSR PC,TYPSTR ;"SCALAR "
MOV #OUTBUF,R0 ;
TYPVL2: LDF (R2),AC0 ;
JSR PC,CVG ;
MOV #OUTBUF,R0 ;
JSR PC,TYPSTR ;
TYPVL3: MOV #CRLFX,R0 ;CRLF
JSR PC,TYPSTR ;
MOV (SP)+,R2 ;Restore R2
RTS PC ;Done
TYPVL4: MOV #VNAME,R0 ;
JSR PC,TYPSTR ;"VECTOR "
MOV #OUTBUF,R0 ;
LDF (R2)+,AC0 ;
JSR PC,CVG ;
LDF (R2)+,AC0 ;
JSR PC,CVG ;
BR TYPVL2 ;Bum code for last field.
TYPVL5: MOV #TNAME,R0 ;
JSR PC,TYPSTR ;"TRANS "
MOV R3,-(SP) ;Save R3
MOV #4,R3 ;R3 ← Number of rows
TYPVL6: MOV #CRLFX,R0 ;
JSR PC,TYPSTR ;
MOV #OUTBUF,R0 ;
LDF (R2),AC0 ;
JSR PC,CVG ;
LDF 20(R2),AC0 ;
JSR PC,CVG ;
LDF 40(R2),AC0 ;
JSR PC,CVG ;
LDF 60(R2),AC0 ;
JSR PC,CVG ;
MOV #OUTBUF,R0 ;
JSR PC,TYPSTR ;
ADD #4,R2 ;Next row
SOB R3,TYPVL6 ;
MOV (SP)+,R3 ;Restore R3
BR TYPVL3 ;Go to the exit stage
SNAME: ASCIE /SCALAR /
VNAME: ASCIE /VECTOR /
TNAME: ASCIE /TRANS /
;I/O routines: TYPR50, INCHR, INOCT, INR50
;Type contents of R0 as RAD50
TYPR50: MOV R0,R1 ;Arg in R1
CLR -(SP) ;Sentinel
JSR PC,TPR51 ;
TST (SP)+ ;
TPR54: RTS PC ;Done
TPR51: CLR R0
DIV #50,R0 ;Do one reduction
BEQ TPR52 ;Down to zero yet?
MOV R1,-(SP) ;Stack remainder.
MOV R0,R1
JSR PC,TPR51 ;And do it again.
MOV (SP)+,R1 ;R1 ← saved remainder.
TPR52: TST R1 ;Zero?
BEQ TPR54 ;Yes. Flush it.
CMP R1,#33 ;Letter, dollar?
BLT TPRLET ;Yes, letter
BEQ TPRDOL ;Yes, dollar
CMP R1,#35 ;Percent?
BEQ TPRPER ;Yes
ADD #22,R1 ;point or number
TPR53: MOV R1,R0 ;Ready to print
JMP TYPCHR ;TYPCHR will do the returning
TPRLET: ADD #100,R1
BR TPR53
TPRDOL: MOV #'$,R0
JMP TYPCHR
TPRPER: MOV #'%,R0
JMP TYPCHR
; Waits for a character to be typed, returns it in R0. Does not echo.
INCHR: TST OUTSW ;VT05 or console?
BEQ INCHR2 ;console
TSTB KBIS ;VT05 input ready?
BNE INCHR1 ;Yes.
INCHR3: SLEEP #1 ;No. Wait a while
BR INCHR ;And try again
INCHR1: MOVB KBIR,R0 ;Get a character
BIC #177600,R0 ;Make off to make it 7 bits
RTS PC ;Done
INCHR2: MOV IREG,R0 ;Get a character
BEQ INCHR3 ;Nothing there
CLR IREG ;Clear it for next character
RTS PC ;Done.
INR50:
COMMENT ⊗ Reads an alphameric string, returns the RAD50
representation in R0 and R1. Any characters after the 6th are lost.
Input terminated by any illegal RAD50 character. Backspace works. ⊗
INOCT:
COMMENT ⊗ Reads an octal number, returns it in R0. Any non-digit
terminates the number. Backspace will work properly. Echoes. ⊗
MOV R2,-(SP) ;Save R2
CLR R2 ;R2 is the eventual result
INCT3: JSR PC,INCHR ;R0 ← Character
CMP #177,R0 ;Backspace?
BNE INCT4 ;No
ASH #-3,R2 ;Get rid of last digit
MOV #DBS,R0 ;Peform deleting backspace. Defined in HALIO
JSR PC,TYPSTR ;
BR INCT3 ;Go back.
INCT4: CMP #'0,R0 ;Too small?
BGT INCT1 ;yes
CMP #'7,R0 ;Too large?
BGE INCT2 ;no
INCT1: MOV #40,R0 ;type a trailing " "
JSR PC,TYPCHR ;
MOV R2,R0 ;R0 ← result
MOV (SP)+,R2 ;Restore R2
RTS PC ;Done
INCT2: MOV R0,-(SP) ;Save the character
JSR PC,TYPCHR ;Echo it
ASH #3,R2 ;Compute new result
BIC #60,(SP) ;
ADD (SP)+,R2 ;
BR INCT3 ;And repeat
; BRACE
BRACE:
COMMENT ⊗
This routine can be called from anywhere. It expects that IPC(R4)
has been bumped once since the last instruction was fetched, that is,
the instruction is at IPC(R4)-2. The currently implemented
operations are:
DDT go to DDT, where <alt>P will return to here.
PROCEED exits this routine to whoever called it.
BREAK <adr> puts a breakpoint at <adr>
TRACE <adr> puts a tracepoint at <adr>
UNBRACE <adr> removes all bracepoints from <adr>
EXAMINE <lev-of>examines a variable
SINGLE STEP puts a trap on the next instruction, proceeds.
RESET remove all breakpoints.
When this routine exits, it has put the psop that it found in R0. If
the psop was <BREAK>, then the correct equivalent is either <NOOP>
for bad entry or the old psop for bracepoints. ⊗
;look up the instruction in the brace table.
MOV R2,-(SP) ;Save R2
MOV IPC(R4),R0 ;
SUB #2,R0 ;R0 ← address of broken instruction
JSR PC,FNDBRK ;R1 ← LOC[entry in break table], 0 for none found. R0←R0
MOV R1,R2 ;R2 ← LOC[entry in break table]
BNE BRK1 ;if any
MOV #BRKDUM,R2 ;nope. use the dummy break instruction.
MOV (R0),OLDPSOP(R2) ;initialize it.
MOV R0,OLDADR(R2);
MOV #ALDBRK,BRCWHA(R2) ;
BR BRK2 ;We know it is a break
;see if it is a break or a trace
BRK1: BIT #ALDSS,DEBMOD(R4) ;Single step?
BEQ BRK3 ;No
BIC #ALDSS,DEBMOD(R4) ;Turn it off.
MOV #BRKM00,R0 ;":SS:<cr>"
JSR PC,TYPSTR ;
BR BRK5 ;And otherwise just like a break.
BRK3: BIT #ALDBRK,BRCWHA(R2) ;Is the break bit on?
BNE BRK2 ;Yes
BIT #ALDTRC,BRCWHA(R2) ;The trace bit, then?
BEQ BRK4 ;No.
;take care of trace case
TRACE: MOV #TRCMS,R0 ;Yes. "<cr>:TRC:"
JSR PC,TYPSTR ;
MOV IPC(R4),R0 ;
SUB #2,R0 ;R0 ← LOC[psop]
JSR PC,TYPADR ;Tell where we are.
MOV OLDPSOP(R2),R0;Tell what psop
MOV OLDADR(R2),R1;
ADD #2,R1 ;R1 ← LOC[argument(s)]
JSR PC,TPPSOP ;
JMP BRKPC1 ;Go to the return place.
BRK4: MOV (SP)+,R2 ;Restore R2
RTS PC ;And exit.
;take care of break case
BRK2: MOV #BRKMS1,R0 ;":BRK:<cr>"
JSR PC,TYPSTR ;
BRK5: MOV IPC(R4),R0 ;
SUB #2,R0 ;R0 ← address of broken instruction
JSR PC,TYPADR ;Tell where we are.
MOV OLDPSOP(R2),R0;Tell what psop
MOV OLDADR(R2),R1;
ADD #2,R1 ;R1 ← LOC[argument(s)]
JSR PC,TPPSOP ;
BRKALD: MOV #BRKMS0,R0 ;Prompt
JSR PC,TYPSTR ;
JSR PC,INCHR ;See what the user wants to do.
CMP #15,R0 ;Carriage return?
BNE BRKPRC ;No.
MOV #CRLFX,R0 ;
JSR PC,TYPSTR ;
BR BRKALD ;
BRKPRC: CMP #'P,R0 ;Proceed?
BNE BRKDDT ;
MOV #BRKMS2,R0 ;
JSR PC,TYPSTR ;
BRKPC1: MOV OLDPSOP(R2),R0 ;Load up the psop
MOV (SP)+,R2 ;Restore R2
RTS PC ;and return
BRKDDT: CMP #'D,R0 ;DDT?
BNE BRKBRK ;
MOV #BRKMS3,R0 ;
JSR PC,TYPSTR ;
BPT ;
BR BRKALD ;
BRKBRK: CMP #'B,R0 ;Break?
BNE BRKUNB ;
MOV #BRKMS4,R0 ;
JSR PC,TYPSTR ;
JSR PC,INADR ;R0 ← address to put a break point.
BEQ BRKHUH ;If reasonable
MOV R0,-(SP) ;Save it
JSR PC,NEWBRK ;R0 ← nice place in the break table
BEQ BRKHUH ;If any
MOV @0(SP),OLDPSOP(R0)
MOV (SP),OLDADR(R0)
MOV #ALDBRK,BRCWHA(R0)
MOV #XBRACE,@(SP)+
BR BRKALD ;
BRKUNB: CMP #'U,R0 ;Unbreak?
BNE BRKREF ;
MOV #BRKMS5,R0 ;
JSR PC,TYPSTR ;
JSR PC,INADR ;R0 ← address to remove break point from.
BEQ BRKHUH ;If reasonable
JSR PC,FNDBRK ;R1 ← LOC[entry in break table], R0 unchanged
BEQ BRKHUH ;
MOV OLDPSOP(R1),@OLDADR(R1) ;Replace old instruction
;note that we do NOT clear the OLDPSOP field; we may need it to proceed.
CLR OLDADR(R1) ;
BR BRKALD ;
BRKREF: CMP #'R,R0 ;Refresh?
BNE BRKVAR ;
MOV #BRKMS8,R0 ;
JSR PC,TYPSTR ;
MOV #BRKNO,R1 ;R1 ← Count of breakpoints
MOV #BRKTAB,R0 ;R0 ← Pointer into break table
BRKR1: TST OLDADR(R0) ;A real break, or empty?
BEQ BRKR2 ;Empty
MOV OLDPSOP(R0),@OLDADR(R0) ;Replace old instruction
;note that we do NOT clear the OLDPSOP field; we may need it to proceed.
CLR OLDADR(R0) ;
BRKR2: SOB R1,BRKR1 ;Repeat as necessary
BR BRKALD ;
BRKVAR: CMP #'E,R0 ;Examine variable?
BNE BRKSS ;
MOV #BRKMS6,R0 ;
JSR PC,TYPSTR ;
JSR PC,INOFS ;R0 ← level-offset of variable
JSR PC,GETARG ;R0 ← LOC[LOC[graph node]
MOV (R0),R0 ;R0 ← LOC[Graph node]
MOV GNVAL(R0),R0;R0 ← LOC[value cell]
JSR PC,TYPVAL ;Print it.
BR BRKALD ;
BRKSS: CMP #'S,R0 ;Single step?
BNE BRKTRC ;
MOV #BRKMS7,R0 ;
JSR PC,TYPSTR ;
BIS #ALDSS,DEBMOD(R4) ;Set for single step
BR BRKPC1 ;and just proceed
BRKTRC: CMP #'T,R0 ;Trace?
BNE BRKHUH ;
MOV #BRKMS9,R0 ;
JSR PC,TYPSTR ;
JSR PC,INADR ;R0 ← address to put a trace point.
BEQ BRKHUH ;If reasonable
MOV R0,-(SP) ;Save it
JSR PC,NEWBRK ;R0 ← nice place in the break table
BEQ BRKHUH ;If any
MOV @0(SP),OLDPSOP(R0)
MOV (SP),OLDADR(R0)
MOV #ALDTRC,BRCWHA(R0)
MOV #XBRACE,@(SP)+
JMP BRKALD ;
BRKHUH: MOV #'π,R0 ;
JSR PC,TYPCHR ;
JMP BRKALD ;
TRCMS: ASCIE </
:TRC: />
BRKM00: ASCIE </
:SS: />
BRKMS0: ASCIE </NU? />
BRKMS1: ASCIE </
:BRK: />
BRKMS2: ASCIE /PROCEED /
BRKMS3: ASCIE /DDT /
BRKMS4: ASCIE /BREAK /
BRKMS5: ASCIE /UNBRACE /
BRKMS6: ASCIE /EXAMINE VARIABLE /
BRKMS7: ASCIE /SINGLE STEP /
BRKMS8: ASCIE /REFRESH /
BRKMS9: ASCIE /TRACE /
; NEWBRK, FNDBRK
FNDBRK:
COMMENT ⊗ Sets R1 to the entry in the break table which corresponds
to the pseudo-code address in R0. Does not change R0. If none is
found, returns 0 in R1. ⊗
MOV R2,-(SP) ;Save R2
MOV #BRKNO,R2 ;R2 ← count of possible breakpoints
MOV #BRKTAB,R1 ;R1 ← Pointer into break table
FNDBR1: CMP R0,OLDADR(R1)
BEQ FNDBR2 ;found
ADD #2*BRKLTH,R1;not yet found
SOB R2,FNDBR1 ;
CLR R1 ;will never find
FNDBR2: MOV (SP)+,R2 ;Restore R2
TST R1 ;So the caller won't have to.
RTS PC ;Done
NEWBRK:
COMMENT ⊗ Finds an empty location in the break table. If there is
none, returns a 0. Result is in R0. ⊗
MOV #BRKTAB,R0 ;First try
FNDB2: TST OLDADR(R0) ;Anything there?
BNE FNDB1 ;Yes.
TST R0 ;So caller won't have to.
RTS PC ;No. All is well
FNDB1: ADD #2*BRKLTH,R0;Try next one.
CMP R0,#BRKDUM ;if any
BLT FNDB2 ;
CLR R0 ;none left
RTS PC ;Done.
; TPPSOP
TPPSOP:
COMMENT ⊗ R0 holds the pseudo-instruction code, R1 points to
the argument (s). Print out the whole thing, using the information
in the ALDOPS for argument types. ⊗
MOV R2,-(SP) ;Save R2
MOV R3,-(SP) ;Save R3
MOV R4,-(SP) ;Save R4
MOV R1,R4 ;R4 ← LOC[argument(s)]
MOV #OPSLTH,R3 ;
MUL R0,R3 ;
ADD #ALDOPS,R3 ;R3 ← ponter into ALDOPS
MOV ALDPNM(R3),R0 ;Print name of psop
JSR PC,TYPR50 ;
MOV ALDPNM+2(R3),R0;
JSR PC,TYPR50 ;
MOV #40,R0 ;" "
JSR PC,TYPCHR ;
MOV ALDARG(R3),R2 ;R2 ← type of arguments
TPPS3: MOV R2,R3 ;
BNE TPPS1 ;Are there more?
MOV (SP)+,R4 ;No. Restore R4
MOV (SP)+,R3 ;Restore R3
MOV (SP)+,R2 ;Restore R2
RTS PC ;Done
TPPS1: CLR R2 ;Yes
DIV #8,R2 ;R2 ← the next type, R3 ← this type
ADD R3,R3 ;Chnage it to byte jump count
JMP @TPPS0(R3) ;go to the appropriate routine
BR TPPS3 ;Then do the next one
TPPS0: 0 ;
TPPSA ;
TPPSLA ;
TPPSO ;
TPPSLO ;
TPPSN ;
TPPSA: MOV (R4)+,R0 ;R0 ← the address
JSR PC,TYPADR ;Print it
BR TPPS3 ;
TPPSLA: MOV (R4)+,R0 ;R0 ← the next address
BEQ TPPS3 ;if any
JSR PC,TYPADR ;Print it
BR TPPSLA ;And do it again.
TPPSO: MOV (R4)+,R0 ;R0 ← level-offset
JSR PC,TYPOFS ;Print it
BR TPPS3 ;
TPPSLO: MOV (R4)+,R0 ;R0 ← level-offset
BEQ TPPS3 ;If any
JSR PC,TYPOFS ;Print it
BR TPPSLO ;And do it again
TPPSN: MOV (R4)+,R0 ;R0 ← the number
JSR PC,TYPOCT ;Print it
MOV #40,R0 ;" "
JSR PC,TYPCHR ;
BR TPPS3 ;
; TYPADR, TYPOFS, INADR, INOFS
TYPADR:
COMMENT ⊗ R0 holds an address in pseudo-code space. Print it out
symbolically. Temporarily, the printout is just octal. ⊗
JSR PC,TYPOCT ;
MOV #40,R0 ;
JSR PC,TYPCHR ;
RTS PC ;
INADR:
COMMENT ⊗ Reads from the tty a symbolic address. Returns the octal
equivalant in R0. Temporarily just reads in octal. If the address
is faulty, returns 0.
⊗
JSR PC,INOCT ;
BIT #1,R0 ;Odd?
BNE INADR2 ;Yes
CMP #PCODE,R0 ;No. In range?
BLE INADR1 ;Yes
INADR2: CLR R0 ;No.
INADR1: TST R0 ;So the caller won't have to.
RTS PC ;
TYPOFS:
COMMENT ⊗ R0 holds a level-offset pair. Print it out symbolically.
Temporarily, the printout is just "<level,offset>" ⊗
MOV R0,-(SP) ;Save the argument
MOV #'<,R0 ;
JSR PC,TYPCHR ;
CLR R0 ;
MOVB 1(SP),R0 ;The level
JSR PC,TYPOCT ;
MOV #',,R0 ;
JSR PC,TYPCHR ;
CLR R0 ;
MOVB (SP)+,R0 ;The offset
JSR PC,TYPOCT ;
MOV #'>,R0 ;
JSR PC,TYPCHR ;
MOV #40,R0 ;" "
JSR PC,TYPCHR ;
RTS PC ;
INOFS:
COMMENT ⊗ Reads from the tty a level-offset pair, which it returns in
R0. Temporarily just reads an octal offset, no level. ⊗
JSR PC,INOCT ;
BIC #177400,R0 ;Just wipe out any level
RTS PC ;
; Not yet implemented
COMMENT ⊗
⊗